import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

public class Client {
	private static ArrayList<String> visited;
	private static Queue<String> queue;
	private static ArrayList<String> links;
	private static ArrayList<String> mails;
	public static final int AMOUNT_OF_SERVERS_THAT_IS_RUNNING_REMOTELY_AND_ACCESSED_WITH_RMI = 10;
	private static long rmi_time;
	private static int fetch_error;

	public static void main(String[] args) {
		try {
			SpiderInterface[] spiders = new SpiderInterface[AMOUNT_OF_SERVERS_THAT_IS_RUNNING_REMOTELY_AND_ACCESSED_WITH_RMI];

			for (int i = 0; i < AMOUNT_OF_SERVERS_THAT_IS_RUNNING_REMOTELY_AND_ACCESSED_WITH_RMI; i++) {

				String host = "rmi://localhost:" + (15000 + i) + "/spider";
				spiders[i] = (SpiderInterface) Naming.lookup(host);
				spiders[i].startCrawling();
			}
			queue = new LinkedList<String>();
			links = new ArrayList<String>();
			mails = new ArrayList<String>();
			visited = new ArrayList<String>();
			queue.add("http://cs.lth.se/kurs/eda095/");
			long start, stop;
			start = System.currentTimeMillis();
			spiders[0].fetchAndSet(visited, queue, links, mails);
			Thread.sleep(5000);
			outerloop: while (true) {
				for (int i = 0; i < AMOUNT_OF_SERVERS_THAT_IS_RUNNING_REMOTELY_AND_ACCESSED_WITH_RMI; i++) {
					fetchAndMerge(spiders[i]);
					if (links.size() + mails.size() >= 2000) {
						stop = System.currentTimeMillis();
						break outerloop;
					}
				}
				System.out.println("Size of queue: " + queue.size());
				System.out.println("number of URLs examined: " + links.size());
				if (queue.size() < AMOUNT_OF_SERVERS_THAT_IS_RUNNING_REMOTELY_AND_ACCESSED_WITH_RMI) {
					setServer(spiders[0], queue.size());
				} else {
					for (int i = 0; i < AMOUNT_OF_SERVERS_THAT_IS_RUNNING_REMOTELY_AND_ACCESSED_WITH_RMI; i++) {
						setServer(
								spiders[i],
								queue.size()
										/ AMOUNT_OF_SERVERS_THAT_IS_RUNNING_REMOTELY_AND_ACCESSED_WITH_RMI);
					}
				}
				Thread.sleep(10000);
			}
			Iterator<String> itr = links.iterator();
			System.out.println("List of URLs:");
			while (itr.hasNext()) {
				System.out.println(itr.next());
			}
			Iterator<String> itr2 = mails.iterator();
			System.out.println("----------------------------");
			System.out.println("List of addresses:");
			while (itr2.hasNext()) {
				System.out.println(itr2.next());
			}
			System.out.println("----- STATISTICS -----");
			System.out.println("Links found:  " + links.size());
			System.out.println("Mails found:  " + mails.size());
			System.out.println("Queue length: " + queue.size());
			System.out.println("URLs visited: " + visited.size());
			System.out.println("Seconds run:  " + (stop - start) / 1000);
			System.out.println("Seconds waited for RMI: " + rmi_time / 1000);
			System.out.println("Number of fetch errors: " + fetch_error);
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private static void setServer(SpiderInterface sp, int amount)
			throws RemoteException {
		Queue<String> newQueue = new LinkedList<String>();
		for (int i = 0; i <= amount; i++) {

			newQueue.add(queue.poll());
		}

		ArrayList<Collection<String>> lists;
		long start = System.currentTimeMillis();
		lists = sp.fetchAndSet(visited, newQueue, links, mails);
		rmi_time += (System.currentTimeMillis() - start);
		ArrayList<String> serverVisited = (ArrayList<String>) lists.get(0);
		Queue<String> serverQueue = (Queue<String>) lists.get(1);
		ArrayList<String> serverLinks = (ArrayList<String>) lists.get(2);
		ArrayList<String> serverMails = (ArrayList<String>) lists.get(3);
		for (String u : serverVisited) {
			if (!visited.contains(u)) {
				visited.add(u);
			}
		}

		for (String u : serverLinks) {
			if (!links.contains(u)) {
				links.add(u);
			}
		}
		for (String u : serverMails) {
			if (!mails.contains(u)) {
				mails.add(u);
			}
		}
		for (String u : serverQueue) {
			if (!queue.contains(u)) {
				queue.add(u);
			}
		}

	}

	private static void fetchAndMerge(SpiderInterface sp)
			throws RemoteException {
		ArrayList<Collection<String>> lists = null;
		boolean gotzIt = false;
		long start = System.currentTimeMillis();
		while (!gotzIt) {
			try {
				lists = sp.fetch();
				gotzIt = true;
			} catch (Exception e) {
				fetch_error++;
			}
		}
		rmi_time += (System.currentTimeMillis() - start);
		ArrayList<String> serverVisited = (ArrayList<String>) lists.get(0);
		Queue<String> serverQueue = (Queue<String>) lists.get(1);
		ArrayList<String> serverLinks = (ArrayList<String>) lists.get(2);
		ArrayList<String> serverMails = (ArrayList<String>) lists.get(3);
		for (String u : serverVisited) {
			if (!visited.contains(u)) {
				visited.add(u);
			}
		}

		for (String u : serverLinks) {
			if (!links.contains(u)) {
				links.add(u);
			}
		}
		for (String u : serverMails) {
			if (!mails.contains(u)) {
				mails.add(u);
			}
		}
		for (String u : serverQueue) {
			if (!queue.contains(u)) {
				queue.add(u);
			}
		}

	}

}
